package handler

import (
	"net/http"
	"strings"

	"database/sql"

	"gitee.com/hp-huiw/family-expense-api/internal/middleware"
	"gitee.com/hp-huiw/my-go-core/security"
	"gitee.com/hp-huiw/my-go-core/util"
	"github.com/gin-gonic/gin"
)

type APIResponse struct {
	Success bool `json:"success"`
	Payload any  `json:"payload,omitempty"`
}

// Gets claims from token in header.
func GetClaims(ctx *gin.Context) *security.MyClaims {
	// Gets authorization from request header.
	// The string should be like below example:
	// Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MDU3ODIxNzUsImlhdCI6MTYwNTc3ODU3NSwiaWQiOiJ1c2VyLWlkIiwidXNlcm5hbWUiOiJIdWkiLCJyb2xlcyI6WyJBZG1pbiJdfQ.tKdhYNyeqOS_ITIV_F0sKT6N-NBFjxMkPyXAkzT43WQ
	authorizationHeader := strings.TrimSpace(ctx.GetHeader(util.HttpHeaderAuthorization))

	// Gets claims from token in header.
	claims, _, _ := security.CheckAuthorizationHeader(authorizationHeader)

	return claims
}

func GetDatabase(ctx *gin.Context) *sql.DB {
	// dbState, _ := ctx.Get(pkg.DatabaseStateKey)
	// db := dbState.(*sql.DB)

	// return db

	// Retrieve the database from the context using the key
	dbState, exists := ctx.Get(middleware.DatabaseStateKey)

	if !exists {
		// Handles error, database not found in context
		return nil
	}

	db, ok := dbState.(*sql.DB)

	if !ok {
		// Handles error, type assertion failed
		return nil
	}

	return db
}

// Sends the raw result to client with http status code OK.
// It will not wrap the response with default map structure.
func SendRawDataResponse(ctx *gin.Context, result any) {
	ctx.JSON(http.StatusOK, result)
}

// Sends the result to client with http status code OK.
// With tag success = true.
// This typically used to send a customized response to client.
func SendDataResponse(ctx *gin.Context, result any) {
	response := getDefaultDataResponse(result)
	ctx.JSON(http.StatusOK, response)
}

// Sends the result to client with http status code OK.
// With tag success = false.
// This typically used to send a customized error to client.
// This is NOT a http status error.
func SendUnsuccessResponse(ctx *gin.Context, result any) {
	response := getDataResponse(false, result)
	ctx.JSON(http.StatusOK, response)
}

// Sends the specific http status code to client.
func SendStatusResponse(ctx *gin.Context, statusCode int) {
	ctx.Status(statusCode)
}

// Aborts current request and sends http status code and result.
// The result might be error specific info.
func AbortWithStatusData(ctx *gin.Context, statusCode int, result any) {
	ctx.AbortWithStatusJSON(statusCode, result)
}

// Gets the default data response which includes a key named "success" and its value is true.
// The key named "payload" holds the data result.
func getDefaultDataResponse(payload any) APIResponse {
	return getDataResponse(true, payload)
}

// Gets the default data response which includes a key named "success" and its value is true.
// The key named "payload" holds the data result.
func getDataResponse(success bool, payload any) APIResponse {
	return APIResponse{
		Success: success,
		Payload: payload,
	}
}
